package base

import (
	"context"
	"os"
	"sync"

	"github.com/liyaozong/mengo/common/di"
	"github.com/liyaozong/mengo/core/base/container"
	"github.com/liyaozong/mengo/core/base/interfaces"

	"github.com/liyaozong/mengo/contracts/logger"
)

// Deferred defines the signature of a function returned by RunAndReturnWaitGroup that should be executed via defer.
type Deferred func()

func RunAndReturnWaitGroup(
	ctx context.Context,
	cancel context.CancelFunc,
	serviceKey string,
	serviceConfig interfaces.Configuration,
	dic *di.Container,
	useSecretProvider bool,
	handlers []interfaces.BootstrapHandler) (*sync.WaitGroup, Deferred, bool) {

	// var err error
	var wg sync.WaitGroup
	deferred := func() {}

	// Check if service provided an initial Logging Client to use. If not create one and add it to the DIC.
	lc := container.LoggingClientFrom(dic.Get)
	if lc == nil {
		lc = logger.NewClient(serviceKey, logger.InfoLog)
		dic.Update(di.ServiceConstructorMap{
			container.LoggingClientInterfaceName: func(get di.Get) interface{} {
				return lc
			},
		})
	}

	dic.Update(di.ServiceConstructorMap{
		container.ConfigurationInterfaceName: func(get di.Get) interface{} {
			return serviceConfig
		},
	})

	// call individual bootstrap handlers.
	startedSuccessfully := true
	for i := range handlers {
		if !handlers[i](ctx, &wg, dic) {
			cancel()
			startedSuccessfully = false
			break
		}
	}

	return &wg, deferred, startedSuccessfully
}

func Run(
	ctx context.Context,
	cancel context.CancelFunc,
	serviceKey string,
	serviceConfig interfaces.Configuration,
	dic *di.Container,
	useSecretProvider bool,
	handlers []interfaces.BootstrapHandler) {

	wg, deferred, success := RunAndReturnWaitGroup(
		ctx,
		cancel,
		serviceKey,
		serviceConfig,
		dic,
		useSecretProvider,
		handlers,
	)

	if !success {
		// This only occurs when a bootstrap handler has fail.
		// The handler will have logged an error, so not need to log a message here.
		cancel()
		os.Exit(1)
	}

	defer deferred()

	// wait for go routines to stop executing.
	wg.Wait()
}
